#include "udpServer.hpp"
#include "onlineUser.hpp"
#include <memory>
#include <fstream>
#include <unordered_map>
#include <signal.h>
using namespace std;
using namespace Server;



static void Usage(string proc)
{
    cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}

//字典翻译
const std::string dictTxt="./dict.txt";
unordered_map<string,string> dict;

//字符串切割函数
bool CutString(string target,string* key,string* value,string sep)
{
    auto pos=target.find(sep);
    if(pos == string::npos) return false;
    *key=target.substr(0,pos);
    //这里使用sep.size()是为了应对“::”这种分隔符
    *value=target.substr(pos+sep.size());
    return true;
}

//判断是否切割成功
static void debugPrint()
{
    for(auto& dt:dict)
    {
        cout<<dt.first<<"##"<<dt.second<<endl;
    }
}


static void initDict()
{
    //打开文件
    ifstream in(dictTxt,std::ios_base::binary);
    if(!in.is_open())
    {
        cerr<<"open file"<<dictTxt<<"error"<<endl;
        exit(OPEN_ERR);
    }
    string line,key,value;
    //从文件中按行读取
    while (getline(in,line))
    {
        //截取字符串
        if(CutString(line,&key,&value,":"))
        {
            dict.insert(make_pair(key,value));
        }
    }
    in.close();

    cout<<"load dict success..."<<endl;
}
//信号捕捉，实现热加载效果：不重新编译，更新数据
void reload(int signo)
{
    (void)signo;
    initDict();
}

//对message进行处理，完成server通信与业务逻辑解耦

//1.翻译业务处理
void handlerMessage(int sockfd,string clientip,uint16_t clientport,string message)
{
    string response_message;
    auto iter=dict.find(message);
    if(iter==dict.end()) response_message="unknow";
    else response_message=iter->second;

    //处理完毕开始返回客户端
    struct sockaddr_in client;
    bzero(&client,sizeof(client));
    client.sin_family=AF_INET;
    client.sin_addr.s_addr=inet_addr(clientip.c_str());
    client.sin_port=htons(clientport);

    //发送信息
    sendto(sockfd,response_message.c_str(),response_message.size(),0,(struct sockaddr *)&client,sizeof(client));
}


/*业务逻辑2：命令行翻译:将客户端发送的指令经过服务器解释后，将执行结果返回给客户端*/
void execCommand(int sockfd,string clientip,uint16_t clientport,string cmd)
{
    if(cmd.find("rm")!=string::npos
    ||cmd.find("mv")!=string::npos 
    || cmd.find("rmdir")!=string::npos
    ||cmd.find("while")!=string::npos ) 
    {
        cerr<<clientip<<":"<<clientport<<"正在做一个非法操作"<<cmd<<endl;
        return;
    }


    string response;
    //1.cmd命令行解析ls -a -l

    //popen() 函数通过创建一个管道，
    //调用 fork 产生一个子进程，执行一个 shell 以运行命令来开启一个进程
    FILE* fp=popen(cmd.c_str(),"r");//fp指向命令行执行结果
    if(fp==nullptr) response=cmd+"exec failed";
    char line[128];
    while (fgets(line,sizeof(line)-1,fp))//按行读取执行结果
    {
        response += line;
    }
    pclose(fp);

    //发送
    struct sockaddr_in client;
    bzero(&client,sizeof(client));
    client.sin_family=AF_INET;
    client.sin_addr.s_addr=inet_addr(clientip.c_str());
    client.sin_port=htons(clientport);

    //发送信息
    sendto(sockfd,response.c_str(),response.size(),0,(struct sockaddr *)&client,sizeof(client));

}

/*业务三：服务器转发消息：向所有在线成员发送消息*/
OnlineUser onlineuser;
void routeMessage(int sockfd,string clientip,uint16_t clientport,string message)
{   
    if(message=="online") onlineuser.addUser(clientip,clientport);
    if(message=="offline") onlineuser.delUser(clientip,clientport);
    if(onlineuser.isOnline(clientip,clientport))
    {
        //消息的路由
        onlineuser.boardcastMessage(sockfd,clientip,clientport,message);
    }
    else
    {
        struct sockaddr_in client;
        bzero(&client,sizeof(client));
        client.sin_family=AF_INET;
        client.sin_addr.s_addr=inet_addr(clientip.c_str());
        client.sin_port=htons(clientport);

        //发送信息
        string response="请先上线再说话！！！，运行online";
        sendto(sockfd,response.c_str(),response.size(),0,(struct sockaddr *)&client,sizeof(client));

    }
}

int main(int argc,char* argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port=atoi(argv[1]);

    //initDict();
    //debugPrint();
    //signal(2,reload);

    //std::unique_ptr<udpServer> usvr(new udpServer(handlerMessage,port));
    //std::unique_ptr<udpServer> usvr(new udpServer(execCommand,port));
    std::unique_ptr<udpServer> usvr(new udpServer(routeMessage,port));
    
    usvr->initServer();
    usvr->start();

    return 0;
}